﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reactive.Disposables;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace SimpleActor.Test
{
    public interface IClient
    {
    }

    public interface ISampleClient : IClient, IActor
    {
    }

    public interface ISampleClientServant : IClient, IActorServant
    {
    }

    public static class SampleClientFactory
    {
        public static ISampleClient Create(ISampleLoggingService service)
        {
            var servant = new SampleClientServant(service);
            var scheduler = new MessageScheduler<ISampleClientServant>("Client", servant);
            var proxy = new SampleClientProxy(scheduler);
            return proxy;
        }
    }

    internal class SampleClientProxy : ActorProxyBase<ISampleClientServant>, ISampleClient
    {
        public SampleClientProxy(IMessageScheduler<ISampleClientServant> scheduler)
            : base(scheduler)
        {
        }
    }

    internal class SampleClientServant : ActorServantBase, ISampleClientServant
    {
        private readonly ISampleLoggingService service;

        public SampleClientServant(ISampleLoggingService service)
        {
            this.service = service;
        }

        public override void OnStart()
        {
            base.OnStart();

            var subscription = service.Logged.Subscribe(OnLogged);
            Handler.Disposables.Add(subscription);
        }

        public override void OnStop()
        {
            base.OnStop();
        }

        public override void Run()
        {
            Debug.WriteLine("{0:yyyy/MM/dd HH:mm:ss.fff} {1}-Thread / Begin Async Calls", DateTime.Now, Thread.CurrentThread.Name);
            var taskA = service.Log(DateTime.Now, "A");
            var taskB = service.Log(DateTime.Now, "B");
            var taskC = service.Log(DateTime.Now, "C");
            var taskX = service.LogStat();
            Debug.WriteLine("{0:yyyy/MM/dd HH:mm:ss.fff} {1}-Thread / End Async Calls", DateTime.Now, Thread.CurrentThread.Name);

            Task.WaitAll(taskA, taskB, taskC, taskX);

            Debug.WriteLine("{0:yyyy/MM/dd HH:mm:ss.fff} {1}-Thread / Begin Async Calls(delayed)", DateTime.Now, Thread.CurrentThread.Name);
            var taskDA = service.LogDelayed(DateTime.Now, "DA", TimeSpan.FromSeconds(1));
            var taskDB = service.LogDelayed(DateTime.Now, "DB", TimeSpan.FromSeconds(3));
            var taskDC = service.LogDelayed(DateTime.Now, "DC", TimeSpan.FromSeconds(5));
            var taskDX = service.LogStat();
            Debug.WriteLine("{0:yyyy/MM/dd HH:mm:ss.fff} {1}-Thread / End Async Calls(delayed)", DateTime.Now, Thread.CurrentThread.Name);

            Task.WaitAll(taskDA, taskDB, taskDC, taskDX);

            Debug.WriteLine("{0:yyyy/MM/dd HH:mm:ss.fff} {1}-Thread / Begin Calls(waiting for each)", DateTime.Now, Thread.CurrentThread.Name);
            service.Log(DateTime.Now, "I").Wait();
            service.Log(DateTime.Now, "J").Wait();
            service.Log(DateTime.Now, "K").Wait();
            service.LogStat().Wait();
            Debug.WriteLine("{0:yyyy/MM/dd HH:mm:ss.fff} {1}-Thread / End Calls(waiting for each)", DateTime.Now, Thread.CurrentThread.Name);


            Debug.WriteLine("{0:yyyy/MM/dd HH:mm:ss.fff} {1}-Thread / Begin Handle Posted Messages", DateTime.Now, Thread.CurrentThread.Name);
            while (Handler.TryHandleMessage(Timeout.InfiniteTimeSpan).CanNext())
            {
            }
        }

        private void OnLogged(LogRecord record)
        {
            var s = string.Format("{0:yyyy/MM/dd HH:mm:ss.fff} {1}-Thread / OnLogged[{2}]: {3} {4:yyyy/MM/dd HH:mm:ss.fff}",
                DateTime.Now, Thread.CurrentThread.Name, record.ID, record.Message, record.Timestamp);

            Debug.WriteLine(s);
        }
    }
}
